#ifndef __M__LOGGER_H__
#define __M__LOGGER_H__
//  #define _GNU_SOURCE
#include "util.hpp"
#include "format.hpp"
#include "sink.hpp"
#include "message.hpp"
#include "level.hpp"
#include "Looper.hpp"
#include <atomic>
#include <mutex>
#include <cstdarg>
#include <unordered_map>
namespace lyzlog
{
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string &logger_name, Loglevel::value level, Formatter::ptr &formatter, std::vector<LogSink::ptr> &sinks)
            : _logger_name(logger_name),
              _limit_level(level),
              _formatter(formatter),
              _sinks(sinks)
        {
        }
        const std::string getName()
        {
            return _logger_name;
        }
        // 完成构造日志消息对象过程并进行格式化，得到格式化后的字符串，并进行落地输出
        void debug(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 通过传入的参数构造出一个日志消息对象，进行日志的格式化，最终落地
            // // 1.判断当前日志是否达到了输出登记
            if (Loglevel::value::DEBUG < _limit_level)
                return;
            // 2.对fmt格式化字符串和不定参数进行字符串的组织，得到的日志消息的字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf failed" << std::endl;
                return;
            }
            va_end(ap);
            serilize(Loglevel::value::DEBUG, file, line, res);
            // 方式内存泄漏 vasprintf的锅
            free(res);
        }
        void info(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 通过传入的参数构造出一个日志消息对象，进行日志的格式化，最终落地
            // // 1.判断当前日志是否达到了输出登记
            if (Loglevel::value::INFO < _limit_level)
                return;
            // 2.对fmt格式化字符串和不定参数进行字符串的组织，得到的日志消息的字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf failed" << std::endl;
                return;
            }
            va_end(ap);
            serilize(Loglevel::value::INFO, file, line, res);
            // 方式内存泄漏 vasprintf的锅
            free(res);
        }
        void warn(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 通过传入的参数构造出一个日志消息对象，进行日志的格式化，最终落地
            // // 1.判断当前日志是否达到了输出登记
            if (Loglevel::value::WEAR < _limit_level)
                return;
            // 2.对fmt格式化字符串和不定参数进行字符串的组织，得到的日志消息的字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf failed" << std::endl;
                return;
            }
            va_end(ap);
            serilize(Loglevel::value::WEAR, file, line, res);
            // 方式内存泄漏 vasprintf的锅
            free(res);
        }
        void error(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 通过传入的参数构造出一个日志消息对象，进行日志的格式化，最终落地
            // // 1.判断当前日志是否达到了输出登记
            if (Loglevel::value::ERROR < _limit_level)
                return;
            // 2.对fmt格式化字符串和不定参数进行字符串的组织，得到的日志消息的字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf failed" << std::endl;
                return;
            }
            va_end(ap);
            serilize(Loglevel::value::ERROR, file, line, res);
            // 方式内存泄漏 vasprintf的锅
            free(res);
        }
        void fatal(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 通过传入的参数构造出一个日志消息对象，进行日志的格式化，最终落地
            // // 1.判断当前日志是否达到了输出登记
            if (Loglevel::value::FATAL < _limit_level)
                return;
            // 2.对fmt格式化字符串和不定参数进行字符串的组织，得到的日志消息的字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf failed" << std::endl;
                return;
            }
            va_end(ap);
            serilize(Loglevel::value::FATAL, file, line, res);
            // 方式内存泄漏 vasprintf的锅
            free(res);
        }

    protected:
        void serilize(const Loglevel::value &level, const std::string &file, size_t line, const char *res)
        {
            // 3.构造LogMsg对象
            LogMsg msg(level, file, line, _logger_name, res);
            // 4.通过格式化工具对于LogMsg进行格式化，得到格式化后的日志字符串
            std::stringstream ss;
            _formatter->format(ss, msg);
            // 5.进行日志落地
            log(ss.str().c_str(), ss.str().size());
        }
        virtual void log(const char *str, size_t len) = 0;

    protected:
        std::mutex _mutex;                         // 互斥锁
        std::string _logger_name;                  // 日志器名称
        std::atomic<Loglevel::value> _limit_level; // （原子类型的）日志输出限制等级
        Formatter::ptr _formatter;                 // 格式化模块对象
        std::vector<LogSink::ptr> _sinks;          // 日志落地模块数组（一个日志器可能多个落地方向）
    };

    class SyncLogger : public Logger
    {
    public:
        using ptr = std::shared_ptr<SyncLogger>;
        SyncLogger(const std::string &logger_name, Loglevel::value level, Formatter::ptr &formatter, std::vector<LogSink::ptr> &sinks)
            : Logger(logger_name, level, formatter, sinks)
        {
        }

    protected:
        // 同步日志器模块，使用日志器直接输出
        void log(const char *data, size_t len) override
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
            {
                sink->log(data, len);
            }
        }
    };

    class AsyncLogger : public Logger
    {
    public:
        AsyncLogger(const std::string &logger_name, Loglevel::value level, Formatter::ptr &formatter, std::vector<LogSink::ptr> &sinks, AsyncType looper_type)
            : Logger(logger_name, level, formatter, sinks), _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::reallog, this, std::placeholders::_1), AsyncType::ASYNC_SAFE)) {}
        // 将数据写入缓冲区
        void log(const char *data, size_t len)
        {
            _looper->push(data, len);
        }
        // 将数据真正落地（将缓冲区中的数据落地）
        void reallog(Buffer &buf)
        {
            if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
            {
                sink->log(buf.begin(), buf.readAbleSize());
            }
        }

    private:
        AsyncLooper::ptr _looper;
    };

    // 使用建造者模式来创建类，而不是直接让用户建造类，简化用户使用的复杂度
    // 1.抽象一个日志器建造者类（完成日志器对象所需零部件的构造 & 日志器的构造）
    //   1.设置日志器类型
    enum LoggerType
    {
        Sync_log,
        Async_log
    };

    //  2.讲不同类型日志器的创建放在同一个日志器建造者类中完成
    class LoggerBuilder
    {
    public:
        LoggerBuilder()
            : _logger_type(LoggerType::Sync_log),
              _limit_level(Loglevel::value::DEBUG),
              _looper_type(AsyncType::ASYNC_SAFE)
        {
        }
        void BuilderType(LoggerType logger_type) { _logger_type = logger_type; }
        void BuilderUnsafeLooper() { _looper_type = AsyncType::ASYNC_UNSAFE; }
        void BuilderLogName(const std::string &logname) { _logger_name = logname; }
        void BuilderLimitLev(Loglevel::value limit_level) { _limit_level = limit_level; }
        void BuilderFormatter(const std::string &pattern)
        {
            _formatter = std::make_shared<Formatter>(pattern);
        };
        template <typename SinkType, typename... Args>
        void BuilderSink(Args &&...args)
        {
            LogSink::ptr psink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }
        virtual Logger::ptr Build() = 0;

    protected:
        AsyncType _looper_type;
        LoggerType _logger_type;
        std::string _logger_name;         // 日志器名称
        Loglevel::value _limit_level;     // （原子类型的）日志输出限制等级
        Formatter::ptr _formatter;        // 格式化模块对象
        std::vector<LogSink::ptr> _sinks; // 日志落地模块数组（一个日志器可能多个落地方向）
    };

    class LocalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr Build() override
        {
            assert(!_logger_name.empty());
            if (_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                BuilderSink<StdoutSink>();
            }
            if (_logger_type == LoggerType::Async_log)
            {
                return std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);
            }
            return std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
        }
    };

    class LoggerManager
    {
    public:
        static LoggerManager &getInstance()
        {
            static LoggerManager eton;
            return eton;
        }
        void addLogger(Logger::ptr &logger)
        {
            if (hasLogger(logger->getName()))
                return;
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->getName(), logger));
        }
        bool hasLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if (it == _loggers.end())
            {
                return false;
            }
            return true;
        }
        Logger::ptr getLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if (it == _loggers.end())
            {
                return Logger::ptr();
            }
            return it->second;
        }
        Logger::ptr rootLogger()
        {
            return _root_logger;
        }

    private:
        LoggerManager()
        {
            std::unique_ptr<lyzlog::LoggerBuilder> builder(new lyzlog::LocalLoggerBuilder);
            builder->BuilderLogName("root");
            Logger::ptr root_logger = builder->Build();
            _root_logger = root_logger;
            _loggers.insert(std::make_pair("root",_root_logger));
        }

    private:
        std::mutex _mutex;
        Logger::ptr _root_logger;
        std::unordered_map<std::string, Logger::ptr> _loggers;
    };


     class GlobalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr Build() override
        {
            assert(!_logger_name.empty());
            if (_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                BuilderSink<StdoutSink>();
            }
            Logger::ptr logger;
            if (_logger_type == LoggerType::Async_log)
            {
                logger =  std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);
            }
            else{
                logger = std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
            }
            LoggerManager::getInstance().addLogger(logger);
            return logger;
        }
    };
}

#endif